#include "thread_pool.h"
#include "server_util.h"
#include "linked_list.h"

extern ListNode *user_list;

//工具函数都写在这里
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
// 获取当前时间的字符串表示
void get_current_time(char* buffer, size_t size) {
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    strftime(buffer, size, "%Y-%m-%d %H:%M:%S", t);
}
void WriteLog(const char *format, ...) 
{
    pthread_mutex_lock (&log_mutex); 
    FILE *logfile = fopen(LOG_FILE, "a");
    if (logfile == NULL) {
        perror("打开日志文件失败");
        return;
    }

    // 获取当前时间
    char time_str[20];
    get_current_time(time_str, sizeof(time_str));

    // 获取进程 ID 和线程 ID
    pid_t pid = getpid();
    pthread_t tid = pthread_self();

    // 写入时间、进程 ID 和线程 ID

    fprintf(logfile, "[%s] pid: %d, tid: %lu, ", time_str, pid, (unsigned long)tid);

    // 写入自定义的日志信息
    va_list args;
    va_start(args, format);
    vfprintf(logfile, format, args);
    va_end(args);
    // 换行符
    fprintf(logfile, "\n");
    printf("[%s] pid: %d, tid: %lu,",time_str, pid, (unsigned long)tid);
    //va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
    printf("\n");

    //
    fclose(logfile);
    pthread_mutex_unlock (&log_mutex); 
}


/* 
 * 函数名：         GetIniKeyString 
 * 入口参数：        title 
 *                      配置文件中一组数据的标识 
 *                  key 
 *                      这组数据中要读出的值的标识 
 *                  filename 
 *                      要读取的文件路径 
 * 返回值：         找到需要查的值则返回正确结果 0 
 *                  否则返回-1 
 */ 



int GetIniKeyString(char *section, char *key, char *filename, char *buf)
{
    FILE *fp;

    // 用来标记是否找到section
    int flag = 0;
    char sSection[64], *wTmp;
    char sLine[1024];
    //filename = "/cloud-service/conf/server.conf";
    // 节section字符串
    sprintf(sSection, "[%s]", section);

    if (NULL == (fp = fopen(filename, "r")))
    {
        printf("open %s failed: %s.\n", filename, strerror(errno));
        return -1;
    }

    // 读取ini中的每一行
    while (NULL != fgets(sLine, 1024, fp))
    {
        // 处理ini文件中的注释行
        if ('#' == sLine[0])
            continue;

        if (';' == sLine[0])
            continue;

        // 定位=的位置
        wTmp = strchr(sLine, '=');
        if ((NULL != wTmp) && (1 == flag))
        {
            if (0 == strncmp(key, sLine, strlen(key)))
            {
                sLine[strlen(sLine) - 1] = '\0';

                while (*(wTmp + 1) == ' ')
                {
                    wTmp++;
                }

                // 获取key对应的value
                strcpy(buf, wTmp + 1);

                fclose(fp);
                return 0;
            }
        }
        else
        {
            if (0 == strncmp(sSection, sLine, strlen(sSection)))
            {
                // 不存在键值对的情况下，标记flag
                flag = 1;
            }
        }
    }

    fclose(fp);
    return -1;
}


/*
 * 参数：
 * section:  配置文件中的节sectin
 * key:      配置项的标识
 * val:      配置项标识对应的值
 * filename: ini配置文件路径
 *
 * 返回值：    成功返回结果0，否则返回-1
 */
int PutIniKeyString(char *section, char *key, char *val, char *filename)
{
    FILE *fpr, *fpw;
    int flag = 0;
    int ret;
    char sLine[1024], sSection[32], *wTmp;

    sprintf(sSection, "[%s]", section);

    if (NULL == (fpr = fopen(filename, "r")))
        return -1;

    // 临时文件名
    sprintf(sLine, "%s.tmp", filename);

    fpw = fopen(sLine, "w+");
    if (NULL == fpw)
        return -1;

    while (NULL != fgets(sLine, 1024, fpr))
    {
        if (2 != flag)
        {
            wTmp = strchr(sLine, '=');
            if ((NULL != wTmp) && (1 == flag))
            {
                if (0 == strncmp(key, sLine, strlen(key)))
                {
                    // 找到对应的key
                    flag = 2;
                    sprintf(wTmp + 1, " %s\n", val);
                }
            }
            else
            {
                if (0 == strncmp(sSection, sLine, strlen(sSection)))
                {
                    // 找到section的位置
                    flag = 1;
                }
            }
        }

        // 写入临时文件
        fputs(sLine, fpw);
    }

    fclose(fpr);
    fclose(fpw);

    sprintf(sLine, "%s.tmp", filename);

    // rename函数在windows上和linux上表现有差异，看文章中的备注
    ret = rename(sLine, filename);
    if (ret != 0)
    {
        if (errno == EEXIST)
        {
            // 如果目标文件已经存在，需要先删除，再重命名
            if (remove(filename) == 0)
            {
                if (rename(sLine, filename) == 0)
                {
                    // printf("File %s has been renamed to %s\n", sLine, filename);
                    return 0;
                }
            }
        }
    }

    return ret;
}

//获取文件打大小
long get_file_size(const char* filename) 
{
    struct stat st;
    if (stat(filename, &st) == 0) {
        return st.st_size;
    } else {
        // 处理错误
        return 0;
    }
}

user_info_t *return_user(task_t *task) {
    ListNode *node = user_list;
    while (node != NULL) {
        user_info_t *user = (user_info_t *)node->val;
        if (user->net_fd == task->peerfd) {
            return user;
        }
        node = node->next;
    }
    return NULL;
}
